﻿using MQTTnet;
using MQTTnet.Client;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.IO.Ports;
using System.Security.Cryptography;
using System.Speech.Synthesis;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace JHQC
{
    public partial class OptView : Form
    {
        List<SerialPort> ser_scanners = new List<SerialPort>();
        SerialPort ser_data;
        SerialPort ser_trigger;
        string mqttTopic;
        IMqttClient mqttClient;
        string playVoice = "false";
        string fullscreen = "false";
        string logPath;
        private List<OptItem> Items;
        public OptView()
        {
            logPath = "./" + DateTime.Now.ToString("yyMMdd") + ".log";
            InitializeComponent();
            textBox1.Focus();

            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            var scanner_coms = config.AppSettings.Settings["scaner"].Value;
            var data_com = config.AppSettings.Settings["data"].Value;
            var trigger_com = config.AppSettings.Settings["trigger"].Value;

            playVoice = config.AppSettings.Settings["playVoice"].Value;
            fullscreen = config.AppSettings.Settings["fullscreen"]?.Value;
            if (fullscreen == "true")
            {
                this.WindowState = FormWindowState.Maximized;
                this.TopMost = true;
            }
            var ser_scanner_list = scanner_coms.Split(new char[] { ',','，'},StringSplitOptions.RemoveEmptyEntries);
            foreach (var ser_scanner_com in ser_scanner_list)
            {
                var ser_scanner = new SerialPort(ser_scanner_com, 9600, Parity.None, 8, StopBits.One);
                ser_scanner.DataReceived += Ser_scanner_DataReceived;
                ser_scanners.Add(ser_scanner);
            }
            ser_data = new SerialPort(data_com, 9600, Parity.None, 8, StopBits.One);
            ser_trigger = new SerialPort(trigger_com, 9600, Parity.None, 8, StopBits.One);
            try
            {
                foreach (var ser_scanner in ser_scanners)
                {
                    ser_scanner.Open();
                }
                ser_trigger.DataReceived += Ser_trigger_DataReceived;
                ser_trigger.Open();
                CreatMqttClient();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + ex.StackTrace);
                Application.Exit();
            }
        }
        MqttClientOptionsBuilder optionsBuilder = null;
        private void CreatMqttClient()
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            var factory = new MqttFactory();
            mqttClient = factory.CreateMqttClient();
            optionsBuilder = new MqttClientOptionsBuilder()
              .WithTcpServer(config.AppSettings.Settings["mqttServer"].Value);
            var user = config.AppSettings.Settings["mqttUid"].Value;
            var pwd = config.AppSettings.Settings["mqttPwd"].Value;
            mqttTopic = config.AppSettings.Settings["mqttTopic"].Value;
            if (!String.IsNullOrEmpty(user) && !String.IsNullOrEmpty(pwd))
                optionsBuilder.WithCredentials(user, pwd);
        }
        void DeepClean(SerialPort port)
        {
            if (port.IsOpen)
            {
                port.DiscardInBuffer();
                port.DiscardOutBuffer();
                port.BaseStream.Flush();

                // 重置硬件流控制
                port.RtsEnable = !port.RtsEnable;
                Thread.Sleep(50);
                port.RtsEnable = !port.RtsEnable;
            }
        }
        private byte[] HexStringToByteArray(string hex)
        {
            if (hex.Length % 2 != 0)
            {
                throw new ArgumentException("HEX字符串长度必须是偶数");
            }

            byte[] bytes = new byte[hex.Length / 2];
            for (int i = 0; i < bytes.Length; i++)
            {
                string hexByte = hex.Substring(i * 2, 2);
                bytes[i] = Convert.ToByte(hexByte, 16);
            }
            return bytes;
        }
        private readonly object _serialLock = new object();

        private async void Ser_trigger_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;
            lock (_serialLock) // 防止多线程重入
            {
                try
                {
                    string trigger = sp.ReadExisting();
                    if (String.IsNullOrWhiteSpace(trigger)) return;
                    File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[触发信息]:" + trigger + "\r\n");
                    if (trigger.Trim() == "1")
                    {
                        Task.Run(() => { HandleTrigger(); });
                    }
                }
                catch (Exception ex)
                {
                    File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[错误日志]:" + ex.Message + "\r\n");
                    DeepClean(sp);
                }
            }
        }
        private static readonly object _serialLock2= new object();

        async void HandleTrigger()
        {
            byte[] buffer = null;
            var hexString = "49310001090004C74493";
            var b = HexStringToByteArray(hexString);
            lock (_serialLock2)
            {
                try
                {
                    ser_data.Open();
                    File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[读取信息]:准备往检测仪发送指令\r\n");
                    ser_data.Write(b, 0, b.Length);
                    Thread.Sleep(200);
                    var blen = ser_data.BytesToRead;
                    buffer = new byte[blen];
                    ser_data.Read(buffer, 0, blen);
                }
                catch (Exception ex)
                {
                    File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[错误日志]:" + ex.Message + "\r\n");
                }
                finally
                { 
                    ser_data.Close();
                }
            }
            try
            {
                StringBuilder sb = new StringBuilder();
                foreach (var v in buffer)
                {
                    sb.Append(((int)v).ToString("X2"));
                }
                var data = sb.ToString();
                File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[出站信息]:" + data + "\r\n");
                data = data.Trim();
                if (data.Length < 240) return;
                data = data.Substring(16, 224);
                var decoder = new Decorder();
                for (int i = 0; i < Items.Count; i++)
                {
                    if (Items[i].Status == StatusEnum.Waiting)
                    {
                        var json = decoder.make_json(data, Items[i].QrCode);
                        int retry = 0;
                        while (retry < 3)
                        {
                            retry++;
                            if (!mqttClient.IsConnected) await mqttClient.ConnectAsync(optionsBuilder.Build());
                            else break;
                        }
                        var p = await mqttClient.PublishStringAsync(mqttTopic, json);
                        File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[MQTT]:" + p.ReasonCode + ":" + json + "\r\n");
                        if (!p.IsSuccess) throw new Exception("MQTT错误:" + p.ReasonString);
                        if (json.Contains("不合格")) Outbound(StatusEnum.NotOk);
                        else Outbound(StatusEnum.Ok);
                        return;
                    }
                }
                var action = new Action(() => { panel1.BackColor = Color.DarkRed; });
                if (panel1.InvokeRequired)
                {
                    panel1.Invoke(action);
                }
                else
                {
                    panel1.BackColor = Color.DarkRed;
                }
                PlayVoice("发生错误");
                File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[提示信息]:MQTT发布成功\r\n");
            }
            catch (Exception ex)
            {
                MessageBox.Show("严重错误，请立即停止作业并联系服务人员解决。");
                File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[错误日志]:" + ex.Message + "\r\n");
            }
        }

        ~OptView()
        {
            foreach (var ser_scanner in ser_scanners)
            {
                ser_scanner.Close();
            }
            ser_data.Close();
            ser_trigger.Close();
        }
        object locker = new object();
        object locker2 = new object();
        private void Reflesh()
        {
            lock (locker)
            {
                while (Items.Count > flowLayoutPanel1.Controls.Count)
                {
                    var prodView = new ProdView();
                    flowLayoutPanel1.Controls.Add(prodView);
                }
                for (int i = 0; i < flowLayoutPanel1.Controls.Count; i++)
                {
                    var prodView = flowLayoutPanel1.Controls[i] as ProdView;
                    prodView.SetItem(Items[Items.Count - i - 1]);
                }
                if (Items.Count > 0)
                    label4.Text = Items[Items.Count - 1].ToViewStr();
                else
                    label4.Text = "--";
                for (int i = Items.Count; i > 0; i--)
                {
                    if (Items[i - 1].Status == StatusEnum.Ok)
                    {
                        label3.Text = Items[i - 1].ToViewStr();
                        label3.ForeColor = Color.Green;
                        break;
                    }
                    else if (Items[i - 1].Status == StatusEnum.NotOk)
                    {
                        label3.Text = Items[i - 1].ToViewStr();
                        label3.ForeColor = Color.Red;
                        break;
                    }
                }
            }
        }
        object  locker3= new object();
        private void Inbound(string s)
        {
            File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[入站信息]:" + s + "\r\n");
            s = s.Trim();
            if (!Regex.IsMatch(s, "^[A-Za-z0-9]")) return;
            var item = new OptItem(s);
            lock (locker3)
            {
                if (Items.Exists(r => r.Status == StatusEnum.Waiting && r.QrCode == s))
                {
                    return;//静默模式
                }
                Items.Add(item);
            }
            SqliteDriver.Insert(item.QrCode);
            var action = new Action(() => { Reflesh(); });
            if (flowLayoutPanel1.InvokeRequired || label3.InvokeRequired || label4.InvokeRequired)
            {
                flowLayoutPanel1.Invoke(action);
            }
            else
            {
                Reflesh();
            }
            try
            {
                PlayVoice("送检" + item.ToPlayStr());
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Outbound(StatusEnum statusEnum)
        {
            bool hit = false;
            string playMsg = "";
            for (int i = 0; i < Items.Count; i++)
            {
                if (Items[i].Status == StatusEnum.Waiting)
                {
                    Items[i].Status = statusEnum;
                    SqliteDriver.Remove(Items[i].QrCode);
                    hit = true;
                    try
                    {
                        string tips = "";
                        if (statusEnum == StatusEnum.Ok)
                        {
                            tips = "合格";
                        }
                        else if (statusEnum == StatusEnum.NotOk)
                        {
                            tips = "不良";
                        }
                        playMsg = tips + Items[i].ToPlayStr();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                    break;
                }
            }
            if (hit)
            {
                var action = new Action(() => { Reflesh(); });
                if (flowLayoutPanel1.InvokeRequired || label3.InvokeRequired || label4.InvokeRequired)
                {
                    flowLayoutPanel1.Invoke(action);
                }
                else
                {
                    Reflesh();
                }
                PlayVoice(playMsg);
            }
            else
            {
                panel1.BackColor = Color.DarkRed;
                PlayVoice("发生错误");
            }

        }
        private void Cancle(string s)
        {
            bool c = false;
            s = s.Trim();
            if (s == "exit") this.Close();
            for (int i = Items.Count; i > 0; i--)
            {
                if (Items[i - 1].QrCode == s)
                {
                    if (Items[i - 1].Status == StatusEnum.Waiting)
                    {
                        Items[i - 1].Status = StatusEnum.Cancle;
                        c = true;
                    }
                    SqliteDriver.Remove(Items[i - 1].QrCode);
                    break;
                }
            }
            if (c)
            {
                var action = new Action(() => { Reflesh(); });
                if (flowLayoutPanel1.InvokeRequired || label3.InvokeRequired || label4.InvokeRequired)
                {
                    flowLayoutPanel1.Invoke(action);
                }
                else
                {
                    Reflesh();
                }
                PlayVoice("取消成功");
            }
        }

        private void PlayVoice(string s)
        {
            if (playVoice == "false") return;
            lock (locker2)
            {
                string t = string.Join(" ", s.ToCharArray());
                using (SpeechSynthesizer synth = new SpeechSynthesizer())
                {
                    synth.SelectVoiceByHints(VoiceGender.Male, VoiceAge.Senior, 0, new System.Globalization.CultureInfo("zh-CN"));
                    synth.Speak(t);

                }
            }
        }

        private void textBox1_Leave(object sender, EventArgs e)
        {
            textBox1.Focus();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var v = textBox1.Text;
            textBox1.Clear();
            Cancle(v);
        }
        private void Ser_scanner_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;

            try
            {
                string data = sp.ReadLine();
                if (String.IsNullOrWhiteSpace(data))
                    return;
                Inbound(data);
            }
            catch (Exception ex)
            {
                File.AppendAllText(logPath, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "[错误日志]:" + ex.Message + "\r\n");
                DeepClean(sp);
            }
        }


        private void button2_Click(object sender, EventArgs e)
        {

            Items.Clear();
            SqliteDriver.Clear();
            flowLayoutPanel1.Controls.Clear();
            panel1.BackColor = Color.Green;
            label3.Text = "--";
            label4.Text = "--";
        }

        private void OptView_Load(object sender, EventArgs e)
        {
            SqliteDriver.Init();
            Items = SqliteDriver.Query();
            Reflesh();
        }
    }
}
